package com.youxin.authserver.common.log;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeanUtils;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;

import org.springframework.http.ResponseEntity;

import org.springframework.stereotype.Component;
import org.springframework.util.concurrent.ListenableFutureCallback;


import com.youxin.busfoundation.bean.BaseLogBean;
import com.youxin.busfoundation.bean.log.RequestLogBean;
import com.youxin.busfoundation.common.GlobalConfig;
import com.youxin.busfoundation.config.WebLoadBalancer;
import com.youxin.busfoundation.enums.SystemType;
import com.youxin.busfoundation.net.WebVisitor;
import com.youxin.foundation.utils.JsonUtils;

/**
 * 日志切
 * 
 * @author yingde.cao
 *
 */
@Component
@Aspect
public class LogAspect {
	private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(LogAspect.class);

	@Pointcut("@annotation(com.youxin.authserver.common.log.LogMethod)")
	public void annotationPointCut() {
	}

	@Before("annotationPointCut()")
	public void before(JoinPoint joinPoint) {
		try {
			MethodSignature sign = (MethodSignature) joinPoint.getSignature();
			Method method = sign.getMethod();
			Class<?>[] parameterTypes = method.getParameterTypes();
			RequestLogBean logBean = new RequestLogBean();
			LogMethod logMethod = method.getAnnotation(LogMethod.class);
			String identifier = logMethod.id();
			Object[] signatureArgs = joinPoint.getArgs();
			/**
			 * 判断参数是否为空
			 */
			if (parameterTypes.length > 0) {
				Class<?> lastCls = parameterTypes[parameterTypes.length - 1];
				Method logBeanMethod = findLogBeanMethod(lastCls);
				if (logBeanMethod != null) {
					Object lastParameter = signatureArgs[parameterTypes.length - 1];
					Object returnValue = logBeanMethod.invoke(lastParameter);
					if (returnValue != null) {
						BeanUtils.copyProperties(returnValue, logBean);
					}
				}
				/**
				 * 获取最后一个参数
				 */
				Object lastObject = signatureArgs[signatureArgs.length - 1];
				String[] eventContents = logMethod.eventContent();

				if (eventContents != null && eventContents.length > 0&& !lastCls.equals(HttpServletResponse.class)) {
					Map<String, String> propertyMap = new HashMap<>();
					for (String propertyName : eventContents) {
						try {							
							String[] properties = StringUtils.split(propertyName, '.');
							if (properties.length > 0) {
								Object result = findPropertyMethod(lastObject, lastCls, properties, 0);
								if (result != null) {
									propertyMap.put(properties[properties.length - 1], result.toString());
								}
							}
						} catch (Exception e) {
						}
					}
					if (propertyMap.size() > 0) {
						logBean.setEventContent(JsonUtils.mapToJsonString(propertyMap));
					}
				}

			}

			logBean.setSystemType(SystemType.CP.getValue());
			logBean.setIdentifier(identifier);
			saveLog(logBean);
		} catch (Exception e) {
			logger.error("日志保存异常before:", e);
		}
	}
	
	@After("annotationPointCut()")
	public void after(JoinPoint joinPoint) {
		MethodSignature sign = (MethodSignature) joinPoint.getSignature();
		Method method = sign.getMethod();
	}

	/**
	 * 查找当前的属性的值
	 * 
	 * @param cls
	 * @param propertyName
	 * @return
	 * @throws InvocationTargetException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	private Object findPropertyMethod(Object object, Class<?> cls, String[] properties, int index)
			throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Method[] methods = cls.getMethods();
		String propertyName = "get" + properties[index];
		for (Method method : methods) {
			if (method.getName().replaceFirst("_", "").equalsIgnoreCase(propertyName)) {
				Object result = method.invoke(object);
				if ((index + 1) == properties.length) {
					return result;
				}
				if(result==null)
					return null;
				Class<?> returnTypeCls = method.getReturnType();
				return findPropertyMethod(result, returnTypeCls, properties, index + 1);
			}
		}
		return null;
	}

	private Method findLogBeanMethod(Class<?> cls) {
		Method[] methods = cls.getMethods();
		for (Method method : methods) {
			if (BaseLogBean.class.equals(method.getReturnType())) {
				return method;
			}
		}
		return null;
	}

	/**
	 * 保存日志
	 * 
	 * @param identifier
	 *            标识
	 */
	private void saveLog(RequestLogBean logBean) {
		try {
			LoadBalancerClient loadBalancer = WebLoadBalancer.instance().getLoadBalancer();
			ServiceInstance instance = loadBalancer.choose(GlobalConfig.LOG_SERVICE_NAME);
			if(instance==null)
			{
				return;
			}
			String uri = instance.getUri().toString();
			WebVisitor.instance().httpPostEntityAsyncWithObject(uri + "/save", String.class, logBean,
					new ListenableFutureCallback<ResponseEntity<String>>() {
						@Override
						public void onSuccess(ResponseEntity<String> result) {
						}

						@Override
						public void onFailure(Throwable t) {
							logger.error("日志保存异常Web:", t);
						}
					});
		} catch (Exception e) {
			logger.error("日志保存异常", e);
		}

	}

}
